<?php
//   +----------------------------------------------------------------------
//   | Copyright (c) 2015-2025 http://www.hdphp.cn All rights reserved.
//   | Licensed ( http://www.hdphp.cn/licenses/ )
//   | Author: Jack <sophia2152@qq.com>
//   | 官方网址: http://www.hdphp.cn
//   | 这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和使用。
//   | 任何企业和个人不允许对程序代码以任何形式任何目的再发布。
//   +----------------------------------------------------------------------
namespace app\common\services\system\admin;

use app\common\dao\system\admin\AdminAuthDao;
use app\common\services\BaseServices;
use app\common\services\other\CacheServices;
use Firebase\JWT\ExpiredException;
use hdphp\exceptions\AuthException;
use hdphp\services\CacheService;
use hdphp\utils\ApiErrorCode;
use hdphp\utils\JwtAuth;

/**
 * Class：admin授权服务
 * 创建人：Jack
 * 创建时间：2024/1/13 8:31
 * @package app\services\system\admin
 * @mixin AdminAuthDao
 */
class AdminAuthServices extends BaseServices
{
    /**
     * 构造方法
     * @param AdminAuthDao $dao
     */
    public function __construct(AdminAuthDao $dao)
    {
        $this->dao = $dao;
    }

    /**
     * 注释：获取Admin授权信息
     * 创建人：Jack
     * 创建时间：2024/1/13 8:33
     * @param string $token
     * @return array
     */
    public function parseToken(string $token): array
    {
        /** @var CacheService $cacheService */
        $cacheService = app()->make(CacheService::class);

        if (!$token || $token === 'undefined') {
            throw new AuthException(ApiErrorCode::ERR_LOGIN);
        }
        /** @var JwtAuth $jwtAuth */
        $jwtAuth = app()->make(JwtAuth::class);
        // 设置解析token
        [$id, $type, $auth] = $jwtAuth->parseToken($token);

        // 检测token是否过期
        $md5Token = md5($token);
        if (!$cacheService->hasToken($md5Token) || !($cacheToken = $cacheService->getTokenBucket($md5Token))) {
            $this->authFailAfter($id, $type);
            throw new AuthException(ApiErrorCode::ERR_LOGIN);
        }
        // 是否超出有效次数
        if (isset($cacheToken['invalidNum']) && $cacheToken['invalidNum'] >= 3) {
            if (!request()->isCli()) {
                $cacheService->clearToken($md5Token);
            }
            $this->authFailAfter($id, $type);
            throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
        }

        // 验证token
        try {
            $jwtAuth->verifyToken();
            $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
        } catch (ExpiredException $e) {
            $cacheToken['invalidNum'] = isset($cacheToken['invalidNum']) ? $cacheToken['invalidNum']++ : 1;
            $cacheService->setTokenBucket($md5Token, $cacheToken, $cacheToken['exp']);
        } catch (\Throwable $e) {
            if (!request()->isCli()) {
                $cacheService->clearToken($md5Token);
            }
            $this->authFailAfter($id, $type);
            throw new AuthException(ApiErrorCode::ERR_LOGIN_INVALID);
        }

        // 获取管理员信息
        $adminInfo = $this->dao->get($id);
        if (!$adminInfo || !$adminInfo->id) {
            if (!request()->isCli()) {
                $cacheService->clearToken($md5Token);
            }
            $this->authFailAfter($id, $type);
            throw new AuthException(ApiErrorCode::ERR_LOGIN_STATUS);
        }
        // 修改密码后token立刻过期
        if ($auth !== md5($adminInfo['password'])) {
            throw new AuthException(ApiErrorCode::ERR_LOGIN_STATUS);
        }

        $adminInfo->type = $type;
        return $adminInfo->hidden(['password', 'factor', 'is_delete', 'status'])->toArray();
    }

    /**
     * 注释：token验证失败后事件
     * 创建人：Jack
     * 创建时间：2024/1/13 8:34
     * @param $id
     * @param $type
     * @return void
     */
    protected function authFailAfter($id, $type)
    {
        try {
            $postData = request()->post();
            $rule = trim(strtolower(request()->rule()->getRule()));
            $method = trim(strtolower(request()->method()));
            // 添加商品退出后事件
            if ($rule === 'product/product/<id>' && $method === 'post') {
                $this->saveProduct($id, $postData);
            }
        } catch (\Throwable $e) {
        }
    }

    /**
     * 注释：保存提交数据
     * 创建人：Jack
     * 创建时间：2024/1/13 8:34
     * @param $adminId
     * @param $postData
     * @return void
     */
    protected function saveProduct($adminId, $postData)
    {
        /** @var CacheServices $cacheService */
        $cacheService = app()->make(CacheServices::class);
        $cacheService->setDbCache($adminId . '_product_data', $postData, 68400);
    }

}